# -*- coding: utf-8 -*-
import re
import pandas as pd
from datetime import time
from datetime import datetime

class PERFORMANCE:
    '''负责对程序的性能进行分析,主要依据time.log top.log iotop.log文件来进行分析'''
    def __init__(self,time_log_path,top_log_path,iotop_log_path,top_command,iotop_command,save_path) -> None:
        # 记录程序开始和结束时间的time.log文件路径
        self.time_log_path=time_log_path
        # 记录cpu和mem数据的top.log文件路径
        self.top_log_path=top_log_path
        # 记录磁盘io数据的iotop.log文件路径
        self.iotop_log_path=iotop_log_path
        # 要记录的程序名
        self.top_command=top_command
        self.iotop_command=iotop_command
        # 程序总运行时间
        self.total_seconds=0
        self.get_total_seconds()
        # 用于解析top.log的内容
        self.top_block_list=[]
        self.get_top_block_list_from_top_log()
        # 解析top_block_list
        self.top_result=[]
        self.analyze_cpu_mem()
        # 用于解析iotop.log的内容
        self.iotop_block_list=[]
        self.get_iotop_block_list_from_iotop_log()
        # 解析iotop_block_list
        self.iotop_result=[]
        self.analyze_disk_io()
        # 生成最终excel数据
        self.save_path=save_path
        self.generate_result()

    def get_total_seconds(self):
        '''对time.log进行分析来获取总运行的时间'''
        with open(self.time_log_path,'r') as f:
            content=f.read()
        time_info=re.findall(r'(\d{2}:\d{2}:\d{2})',content,flags=0)
        start_time_str=time_info[0]
        end_time_str=time_info[1]
        start_time=datetime.strptime(start_time_str,'%H:%M:%S')
        end_time=datetime.strptime(end_time_str,'%H:%M:%S')
        self.total_seconds=(end_time-start_time).seconds

    def get_top_block_list_from_top_log(self):
        '''从top.log文件获取top_block_list'''
        # 读取 top 命令记录的文件
        with open(self.top_log_path) as f:
            lines = f.readlines()
        top_block_index_list=[]
        for i in range(len(lines)):
            if lines[i]=='\n' and i!=len(lines) and lines[i+1]=='    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND\n':
                top_block_index_list.append(i-5)
        for i in range(len(top_block_index_list)):
            index=top_block_index_list[i]
            if i!=len(top_block_index_list)-1:
                next_index=top_block_index_list[i+1]
            else:
                next_index=len(lines)
            top_block={'head':lines[index:index+5],'info':lines[index+7:next_index]}
            self.top_block_list.append(top_block)

    def analyze_cpu_mem(self):
        '''对top.log进行分析来获取cpu和内存占用相关信息'''
        for top_block in self.top_block_list:
            # 获取free数值，也就是第三行的id的数值
            heads=top_block['head']
            free=float(re.findall(r'(\d+\.\d+) id,',heads[2],flags=0)[0])
            infos=top_block['info']
            cpu=0
            mem=0
            
            df = pd.DataFrame([one_info.split() for one_info in infos], columns=['PID', 'USER', 'PR', 'NI', 'VIRT', 'RES', 'SHR', 'S', '%CPU', '%MEM', 'TIME+', 'COMMAND'])
            for i in range(len(df['PID'])):
                command=df['COMMAND'][i]    
                # TODO
                if command==self.top_command:
                    cpu+=float(df['%CPU'][i])
                    mem+=float(df['%MEM'][i])
            one_result={'cpu':cpu,'mem':mem,'free':free}
            self.top_result.append(one_result)

    def get_iotop_block_list_from_iotop_log(self):
        '''对iotop.log文件进行解析'''
        # 读取 iotop 命令记录的文件
        with open(self.iotop_log_path) as f:
            lines = f.readlines()
        iotop_block_index_list=[]
        for i in range(len(lines)):
            if lines[i]=='    TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO    COMMAND\n':
                iotop_block_index_list.append(i-2)
        for i in range(len(iotop_block_index_list)):
            index=iotop_block_index_list[i]
            if i!=len(iotop_block_index_list)-1:
                next_index=iotop_block_index_list[i+1]
            else:
                next_index=len(lines)
            iotop_block={'head':lines[index:index+2],'info':lines[index+3:next_index]}
            self.iotop_block_list.append(iotop_block)

    def analyze_disk_io(self):
        '''对iotop.log进行分析来获取磁盘io相关信息'''
        def translate_rate_to_float(rate):
            '''把4.72 M/s转换成4720000.0'''
            unit=re.findall(r'([KBMG])/s',rate,flags=0)[0]
            number=re.findall(r'(\d+\.\d+)',rate,flags=0)[0]
            if unit=='B':
                return float(number)
            if unit=='K':
                return float(number)*1000
            if unit=='M':
                return float(number)*1000*1000
            if unit=='G':
                return float(number)*1000*1000*1000

        for iotop_block in self.iotop_block_list:
            # 获取free数值，也就是第三行的id的数值
            heads=iotop_block['head']
            infos=iotop_block['info']
            io_read_total=0
            io_write_total=0
            for one_info in infos:
                if self.iotop_command in one_info:
                    read_write_tuple_list=re.findall(r'(\d+\.\d+ [KBMG]/s)\s+(\d+\.\d+ [KBMG]/s)\s+',one_info,flags=0)
                    io_read=read_write_tuple_list[0][0]
                    io_write=read_write_tuple_list[0][1]
                    io_read_total+=translate_rate_to_float(io_read)
                    io_write_total+=translate_rate_to_float(io_write)
            self.iotop_result.append({'read':io_read_total,'write':io_write_total})

    def generate_result(self):
        '''生成最终excel数据'''
        def translate_number_to_rate(number):
            '''把6530000.0转换成6.53Mb/s'''
            if number>1000:
                if number>1000*1000:
                    if number>1000*1000*1000:
                        unit='GB/s'
                        number=number/(1000*1000*1000)
                        return str(number)+unit
                    else:
                        unit='MB/s'
                        number=number/(1000*1000)
                        return str(number)+unit
                else:
                    unit='KB/s'
                    number=number/(1000)
                    return str(number)+unit
            else:
                unit='B/s'
                number=number
                return str(number)+unit
        
        cpu_total=0
        mem_total=0
        free_total=0
        read_total=0
        write_total=0
        for item in self.top_result:
            cpu_total+=item['cpu']
            mem_total+=item['mem']
            free_total+=item['free']
        cpu_average=cpu_total/len(self.top_result)
        mem_average=mem_total/len(self.top_result)
        free_average=free_total/len(self.top_result)
        cpu_average=str(cpu_average)+'%'
        mem_average=str(mem_average)+'%'
        free_average=str(free_average)+'%'
        for item in self.iotop_result:
            read_total+=item['read']
            write_total+=item['write']
        read_average=read_total/len(self.iotop_result)
        write_average=write_total/len(self.iotop_result)
        read_average=translate_number_to_rate(read_average)
        write_average=translate_number_to_rate(write_average)
        result={'cpu':[cpu_average],'mem':[mem_average],'free':[free_average],'read':read_average,'write':write_average,'time':self.total_seconds}
        df=pd.DataFrame(result)
        df.to_excel(self.save_path,sheet_name='result')